package com.czie.myapplication;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SensorManager {
    private Map<String, Sensor> sensors;
    private String gatewayId = MainActivity.GATEWAYID;
    String serialServerIp = null;
    public static boolean serialServerConnected = false;
    boolean autoScanSerialServer;
    Socket socket = null;
    InputStream bis = null;
    OutputStream bos = null;

    public static final int SERIAL_SERVER_UDP_PORT = 9902;
    public static final int SERIAL_SERVER_TCP_PORT = 9901;
    private static SensorManager manager = new SensorManager();

    // 开灯：开灯1 gateayId：00000008 网关id为8位字符的字符串，传感器id为16位字符的字符串
    public static String lightSwitch1Id = MainActivity.GATEWAYID + "0C010301";
    // 开灯：开灯02
    public static String lightSwitch2Id = MainActivity.GATEWAYID + "0C010302";
    // 警报：灯光警报器
    public static String alarmSwitchId = MainActivity.GATEWAYID + "0C010303";
    // 通风：开风扇
    public static String fanSwitchId = MainActivity.GATEWAYID + "0C010304";


    private SensorManager() {
        sensors = new HashMap<>();
        autoScanSerialServer = true;
    }

    /**
     * 启动服务
     *
     * @param activity
     * @param gatewayId
     */
    public void startGatherService(Activity activity, String gatewayId) {
        // 传入对应的Activity
        Intent it1 = new Intent(activity, GatherService.class);
        Bundle bundle = new Bundle();
        this.gatewayId = gatewayId;
        // 获取传入的网关Id
        bundle.putString("code", gatewayId);
        // 获取传入的Mqtt服务器地址
        it1.putExtras(bundle);
        activity.startService(it1);
    }

    /**
     * 设置串口服务器Ip
     *
     * @param serialServerIp
     */
    public void setSerialServerIp(String serialServerIp) {
        this.serialServerIp = serialServerIp;
        autoScanSerialServer = false;
    }

    public static SensorManager getManager() {
        return manager;
    }

    private void addSensor(Sensor sensor) {
        sensors.put(sensor.getSensorId(), sensor);
    }

    /**
     * 通过Id获取Sensor
     *
     * @param id
     * @return
     */
    public Sensor getSensor(String id) {
        return sensors.get(id);
    }

    /**
     * 设置网关Id
     *
     * @param gatewayId
     */
    public void setGatewayId(String gatewayId) {
        this.gatewayId = gatewayId;
    }


    /**
     * 扫描串口服务器的IP地址
     *
     * @return 串口服务器IP地址
     */
    public String scanSerialServer() {
        serialServerConnected = false;

        if (!autoScanSerialServer && serialServerIp != null) {
            return serialServerIp;
        }

        serialServerIp = null;
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket(10001);
            socket.setBroadcast(true);
            byte[] buf = {(byte) 0xaf, 0x00, 0x00, 0x00};
            SocketAddress address = new InetSocketAddress("255.255.255.255", SERIAL_SERVER_UDP_PORT);
            DatagramPacket packet = new DatagramPacket(buf, 0, 4, address);
            socket.setSoTimeout(1000);

            socket.send(packet);
            socket.receive(packet);
            serialServerIp = packet.getAddress().getHostAddress();
            // System.out.println(packet.getAddress());
        } catch (IOException e) {
            Log.e("MANAGER", "扫描串口服务器失败");
        } finally {
            if (socket != null) {
                socket.close();
            }
        }
        return serialServerIp;
    }

    /**
     * 连接到串口服务器
     *
     * @return 连接成功返回true，失败返回false
     */
    public boolean connectSerialServer() {
        socket = null;
        bis = null;
        try {
            Log.d("Socket", "连接到串口服务器....");
            socket = new Socket(serialServerIp, SERIAL_SERVER_TCP_PORT);
            socket.setSoTimeout(15000);
            bis = socket.getInputStream();
            bos = socket.getOutputStream();
            serialServerConnected = true;
            Log.d("Socket", "连接串口服务器成功");

            return true;
        } catch (IOException e) {
            Log.e("MANAGER", "连接到串口服务器失败:");
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 控制传感器开操作
     */
    public void switchOn(String switchId) throws IOException {
        byte[] cmd;
        Sensor sensor = sensors.get(switchId);
        Log.e("CONTROL", "===============" + switchId);

        switch (switchId.substring(8)) {
            case "0C010301":
                // 消息头 （0xAF，0x01）+ 数据长度 （0x08）+ + 通道号（0x0通道号） + 开关指令 （0xff ， 0x00）+ 开的指令结尾0xD8
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x00, (byte) 0xFF, 0x00, (byte) 0x8D,
                        (byte) 0xD8};
                break;
            case "0C010302":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, (byte) 0x00, 0x01, (byte) 0xFF, 0x00,
                        (byte) 0xDC, 0x18};
                break;
            case "0C010303":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x02, (byte) 0xFF, (byte) 0x00, 0x2C,
                        0x18};
                break;
            case "0C010304":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x03, (byte) 0xFF, 0x00, 0x7D,
                        (byte) 0xD8};
                break;
            case "0C010305":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x04, (byte) 0xFF, 0x00, (byte) 0xCC,
                        0x19};
                break;
            case "0C010306":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x05, (byte) 0xFF, 0x00, (byte) 0x9D,
                        (byte) 0xD9};
                break;
            case "0C010307":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x06, (byte) 0xFF, 0x00, 0x6D,
                        (byte) 0xD9};
                break;
            case "0C010308":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, 0x03, 0x05, 0x00, 0x07, (byte) 0xFF, 0x00, 0x3C, 0x19};
                break;
            default:
                Log.e("CONTROL", "Not found id:" + switchId.substring(8));
                return;
        }
        bos.write(cmd);
    }

    /**
     * 开关控制
     *
     * @param switchId：被控制的传感器Id
     * @param cmd：控制的指令          1--开    0--关
     * @throws IOException
     */
    public void switchControl(String switchId, int cmd) throws IOException {
        gatewayId = MainActivity.GATEWAYID;
        putSensorData(new DataPacket(gatewayId + "0C010304", Sensor.FAN1_RELAY, "0"));
        putSensorData(new DataPacket(gatewayId + "0C010302", Sensor.LIGHT2_REALY, "0"));
        putSensorData(new DataPacket(gatewayId + "0C010303", Sensor.ALARM_RALAY, "0"));
        putSensorData(new DataPacket(gatewayId + "0C010301", Sensor.LIGHT1_RELAY, "0"));

        DataPacket packet;
        if (cmd == 1) {
            switchOn(switchId);
            Log.d("", "switchControl, Type = " + manager.getSensor(switchId).getType());
            packet = new DataPacket(switchId, manager.getSensor(switchId).getType(), "1");

        } else {
            switchOff(switchId);
            packet = new DataPacket(switchId, manager.getSensor(switchId).getType(), "0");
        }
    }

    /**
     * 控制传感器关操作
     *
     * @param sensorId 传感器编号（控制开关ID：0C010301, 0c010302 0C010303
     *                 0C010304分别代表灯1，灯光报警，灯2，风扇）
     */
    public void switchOff(String sensorId) throws IOException {
        byte[] cmd;
        Sensor sensor = sensors.get(sensorId);

        Log.e("CONTROL", "===============" + sensorId);
        switch (sensorId.substring(8)) {
            case "0C010301":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x00,
                        (byte) 0x00, (byte) 0x00, (byte) 0xCC, (byte) 0x28};
                break;
            case "0C010302":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x01,
                        (byte) 0x00, (byte) 0x00, (byte) 0x9D, (byte) 0xE8};
                break;
            case "0C010303":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x02,
                        (byte) 0x00, (byte) 0x00, (byte) 0x6D, (byte) 0xE8};
                break;
            case "0C010304":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x03,
                        (byte) 0x00, (byte) 0x00, (byte) 0x3C, (byte) 0x28};
                break;
            case "0C010305":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x04,
                        (byte) 0x00, (byte) 0x00, (byte) 0x8D, (byte) 0xE9};
                break;
            case "0C010306":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x05,
                        (byte) 0x00, (byte) 0x00, (byte) 0xDC, (byte) 0x29};
                break;
            case "0C010307":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x06,
                        (byte) 0x00, (byte) 0x00, (byte) 0x2C, (byte) 0x29};
                break;
            case "0C010308":
                cmd = new byte[]{(byte) 0xAF, 0x01, 0x08, 0x00, (byte) 0x03, (byte) 0x05, (byte) 0x00, (byte) 0x07,
                        (byte) 0x00, (byte) 0x00, (byte) 0x7D, (byte) 0xE9};
                break;
            default:
                return;
        }
        bos.write(cmd);
//        if(sensor == null) {
//            Log.e("CONTROL","No sensorid:"+sensorId);
//            return;
//        }
        // sensor.setValue("0");
    }


    /**
     * @return
     * @throws IOException
     */
    public List<DataPacket> receiveData() throws IOException {
        byte[] buf = new byte[512];
        int serialPort;
        int size;

        try {
            while (true) {
                size = bis.read(buf, 0, 4);
                if (size < 4 && size > 0) {
                    Log.w("Socket", "Receive trunked data size");
                    continue;
                } else if (size <= 0) {
                    Log.e("TTTTTTTTT:", "size=" + size);
                    return null;
                } else {
                    break;
                }
            }

            // 接收到数据的长度：21 除去起始字节（1字节）与校验和（1字节）
            int dataLen = ByteIntConvertor.bytesToShort(buf, 2);
            serialPort = buf[1];

            size = bis.read(buf, 0, dataLen);
            // 将解析到的
            List<DataPacket> packets = DataPacket.parse(buf, serialPort, gatewayId);
//			Log.i("RRRRRRRRRRRRR", "接收到传感器数据：数据" + buf[4] + "  类型：" + buf[1] + "  Id" + gatewayId);
            // 将解析完毕的数据添加到存放传感器数据的集合当中。
            for (DataPacket packet : packets) {
                putSensorData(packet);
            }
            return packets;
        } catch (IOException e) {
            e.printStackTrace();
            bis.close();
            bos.close();
            socket.close();
            serialServerConnected = false;
            Log.e("Socket", "网关的连接断开");
            throw e;
        }
    }

    /**
     * 将采集到的数据保存到传感器的数据数组中
     *
     * @param packet - 数据包
     */
    public void putSensorData(DataPacket packet) {
        Sensor sensor = sensors.get(packet.getSensorId());
        long time;
        Date date = new Date();
        time = date.getTime() / 1000;
        if (sensor == null) {
            Log.e("MANNAGER", "SensorManager.class === 传感器不存在，增加传感器：" + packet.getSensorId());
            sensor = new Sensor(packet.getSensorId(), packet.getSensorType());

            sensors.put(sensor.getSensorId(), sensor);
//            for(Sensor s: sensors.values()) {
//            	System.out.println("传感器："+s.getSensorId());
//            }
        }
        sensor.addData(packet.getSensorData(), time);
    }

    /**
     * 返回当前网关下所有的传感器表
     *
     * @return
     */
    public Map<String, Sensor> getSensors() {
        return sensors;
    }

    /**
     * 获取当前的网关ID
     *
     * @return
     */
    public String getGatewayId() {
        return gatewayId;
    }

    /**
     * 获取串口服务器的IP地址
     *
     * @return
     */
    public String getSerialServerIp() {
        return serialServerIp;
    }

    /**
     * 根据传感器类型获取传感器最后一次接收到的数据(默认返回第一个传感器)
     *
     * @return 传感器的数据或null表示没有数据
     */
    public String getSensorValue(int sensorType) {
        Collection<Sensor> list = sensors.values();
        for (Sensor sensor : list) {
            if (sensor.getType() == sensorType) {
                // 返回最新数据
                return sensor.getLatestValue();
            }
        }
        return null;
    }

    /**
     * 根据传感器ID获取传感器最后一次发送过来的数据
     *
     * @param id
     * @return 传感器的数据或null表示没有数据
     */
    public String getSensorValue(String id) {
        Sensor sensor = sensors.get(id);
        if (sensor != null) {
            // 返回传感器最新数据
            return sensor.getLatestValue();
        }
        return null;
    }

    public boolean isGatewayConnected() {
        return serialServerConnected;

    }
}
